import {
  Inject,
  Injectable,
  InternalServerErrorException,
} from '@nestjs/common';
import * as qiniu from 'qiniu';
import * as path from 'path';
import { v4 as uuidv4 } from 'uuid';
import { QINIU_CLIENT } from './qiniu.constants';
import { QiniuOptions } from './qiniu-options.provider';

@Injectable()
export class QiniuService {
  private uploadToken: string;
  private bucket: string;
  private qiniuHost: string;
  private formUploader: qiniu.form_up.FormUploader;
  private bucketManager: qiniu.rs.BucketManager;

  constructor(
    @Inject(QINIU_CLIENT) private readonly qiniuOptions: QiniuOptions,
  ) {}

  init(): void {
    const { accessKey, secretKey, bucket, qiniuHost } = this.qiniuOptions;
    this.qiniuHost = qiniuHost;
    this.bucket = bucket;
    const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
    const config = new qiniu.conf.Config({
      zone: (qiniu.zone as unknown as { Zone_cn_east_2: any }).Zone_cn_east_2, // 空间对应的机房
    });

    // 是否使用https域名
    // config.useHttpsDomain = true;
    // 上传是否使用cdn加速
    // config.useCdnDomain = true;
    function getUploadToken(scope) {
      const options = {
        scope: scope, // 必填, 七牛云控制台添加的空间名称
        expires: 10000, // expires非必填， 在不指定上传凭证的有效时间情况下，默认有效期为1个小时。expires单位为秒
        returnBody:
          '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}',
        // returnBody非必填， 有时候我们希望能自定义这个返回的JSON格式的内容，可以通过设置returnBody参数来实现。
      };
      const putPolicy = new qiniu.rs.PutPolicy(options); // 配置
      const uploadToken = putPolicy.uploadToken(mac); // 获取上传凭证
      return uploadToken;
    }

    this.uploadToken = getUploadToken(bucket);
    this.formUploader = new qiniu.form_up.FormUploader(config);
    this.bucketManager = new qiniu.rs.BucketManager(mac, config);
  }

  async uploadToQiniu(file, dir = ''): Promise<string> {
    this.init();
    const filename =
      `${dir ? dir + '/' : ''}` +
      Date.now() +
      '-' +
      uuidv4() +
      path.extname(file.originalname);
    return new Promise((resolve) => {
      this.formUploader.putFile(
        this.uploadToken,
        filename,
        file.path,
        new qiniu.form_up.PutExtra(),
        (respErr, respBody, respInfo) => {
          if (respErr) {
            console.error(respErr);
            throw new InternalServerErrorException(respErr.message);
          }
          if (respInfo.statusCode == 200) {
            this.qiniuHost + respBody.key;
            resolve(this.qiniuHost + '/' + respBody.key);
          } else {
            console.error(respInfo.statusCode, respBody);
            throw new InternalServerErrorException(respInfo);
          }
        },
      );
    });
  }

  async removeQiniu(key: string) {
    this.init();
    return new Promise((resolve, reject) => {
      this.bucketManager.delete(
        this.bucket,
        key,
        (respErr, respBody, respInfo) => {
          if (respErr) {
            console.error(respErr);
            throw new InternalServerErrorException(respErr.message);
          }
          if (respInfo.statusCode === 200) {
            resolve(respBody);
          } else {
            reject(respInfo);
          }
        },
      );
      return null;
    });
  }

  async getQiniuAll(limit = 3) {
    this.init();
    return new Promise((resolve, reject) => {
      this.bucketManager.listPrefix(
        this.bucket,
        { limit },
        (respErr, respBody, respInfo) => {
          if (respErr) {
            console.error(respErr);
            throw new InternalServerErrorException(respErr.message);
          }
          if (respInfo.statusCode === 200) {
            console.log('respBody', respBody);
            resolve(respBody);
          } else {
            reject(respInfo);
          }
        },
      );
    });
  }
}
